package com.my.chapter14;

import java.util.*;

public class practice11 {
    public static void main(String[] args) {
        //LiteralPetCreator1.main(args);
        PetCount.main(args);
    }
}

class Pet{
    public Pet(String name){}
    public Pet(){}

    @Override
    public String toString() {
        return "Pet";
    }
}

class Dog extends Pet{
    public Dog(String name){super(name);}
    public Dog(){super();}

    @Override
    public String toString() {
        return "Dog";
    }
}

class Mutt extends Dog{
    public Mutt(String name){super(name);}
    public Mutt(){super();}

    @Override
    public String toString() {
        return "Mutt";
    }
}

class Pug extends Dog{
    public Pug(String name){super(name);}
    public Pug(){super();}

    @Override
    public String toString() {
        return "Pug";
    }
}

class Cat extends Pet{
    public Cat(String name){super(name);}
    public Cat(){super();}

    @Override
    public String toString() {
        return "Cat";
    }
}

class EgyptianMau extends Pet{
    public EgyptianMau(String name){super(name);}
    public EgyptianMau(){super();}

    @Override
    public String toString() {
        return "EgyptianMau";
    }
}

class Manx extends Pet{
    public Manx(String name){super(name);}
    public Manx(){super();}

    @Override
    public String toString() {
        return "Manx";
    }
}

class Cymric extends Manx{
    public Cymric(String name){super(name);}
    public Cymric(){super();}

    @Override
    public String toString() {
        return "Cymric";
    }
}

class Rodent extends Pet{
    public Rodent(String name){super(name);}
    public Rodent(){super();}

    @Override
    public String toString() {
        return "Rodent";
    }
}

class Rat extends Rodent{
    public Rat(String name){super(name);}
    public Rat(){super();}

    @Override
    public String toString() {
        return "Rat";
    }
}

class Mouse extends Rodent{
    public Mouse(String name){super(name);}
    public Mouse(){super();}

    @Override
    public String toString() {
        return "Mouse";
    }
}

class Hamster extends Rodent{
    public Hamster(String name){super(name);}
    public Hamster(){super();}

    @Override
    public String toString() {
        return "Mouse";
    }
}

class Gerbil extends Pet{
    public Gerbil(String name){super(name);}
    public Gerbil(){super();}

    @Override
    public String toString() {
        return "Gerbil";
    }
}

abstract class PetCreator{
    private Random rand = new Random(47);
    public abstract List<Class<? extends Pet>> types();
    public Pet randomPet(){
        int n = rand.nextInt(types().size());
        try {
            return types().get(n).newInstance();
        }catch (InstantiationException e){
            throw new RuntimeException(e);
        }catch (IllegalAccessException e){
            throw new RuntimeException(e);
        }
    }
    public Pet[] createArray(int size){
        Pet[] result = new Pet[size];
        for(int i=0;i<size;i++){
            result[i] = randomPet();
        }
        return result;
    }
    public ArrayList<Pet> arrayList(int size){
        ArrayList<Pet> result = new ArrayList<Pet>();
        Collections.addAll(result,createArray(size));
        return result;
    }
}

@SuppressWarnings("unchecked")
class ForNameCreator extends PetCreator {
    private static List<Class<? extends Pet>> types =
            new ArrayList<Class<? extends Pet>>();
    // Types that you want to be randomly created:
    private static String[] typeNames = {
            "com.my.chapter14.Mutt",
            "com.my.chapter14.Pug",
            "com.my.chapter14.EgyptianMau",
            "com.my.chapter14.Manx",
            "com.my.chapter14.Cymric",
            "com.my.chapter14.Rat",
            "com.my.chapter14.Mouse",
            "com.my.chapter14.Hamster",
            "com.my.chapter14.Gerbil"
    };
    static {
        try {
            for(String name : typeNames)
                types.add(
                        (Class<? extends Pet>)Class.forName(name));
        } catch(ClassNotFoundException e) {
            throw new RuntimeException(e);
        }
    }
    public List<Class<? extends Pet>> types() {return types;}
}

@SuppressWarnings("unchecked")
class LiteralPetCreator1 extends PetCreator {
    // No try block needed.
    public static final List<Class<? extends Pet>> allTypes =
            Collections.unmodifiableList(Arrays.asList(
                    Pet.class, Dog.class, Cat.class, Rodent.class,
                    Mutt.class, Pug.class, EgyptianMau.class, Manx.class,
                    Cymric.class, Rat.class, Mouse.class,Hamster.class,
                    Gerbil.class));
    // Types for random creation:
    private static final List<Class<? extends Pet>> types =
            allTypes.subList(allTypes.indexOf(Mutt.class),
                    allTypes.size());
    public List<Class<? extends Pet>> types() {
        return types;
    }
    public static void main(String[] args) {
        System.out.println(types);
    }
}

class PetCount {
    static class PetCounter extends HashMap<String, Integer>{
        public void count(String type) {
            Integer quantity = get(type);
            if(quantity == null)
                put(type, 1);
            else
                put(type, quantity + 1);
        }
    }
    public static void
    countPets(PetCreator creator) {
        PetCounter counter= new PetCounter();
        for(Pet pet : creator.createArray(20)) {
            // List each individual pet:
            System.out.println(pet.getClass().getSimpleName() + " ");
            if(pet instanceof Pet)
                counter.count("Pet");
            if(pet instanceof Dog)
                counter.count("Dog");
            if(pet instanceof Mutt)
                counter.count("Mutt");
            if(pet instanceof Pug)
                counter.count("Pug");
            if(pet instanceof Cat)
                counter.count("Cat");
            if(pet instanceof Manx)
                counter.count("EgyptianMau");
            if(pet instanceof Manx)
                counter.count("Manx");
            if(pet instanceof Manx)
                counter.count("Cymric");
            if(pet instanceof Rodent)
                counter.count("Rodent");
            if(pet instanceof Rat)
                counter.count("Rat");
            if(pet instanceof Mouse)
                counter.count("Mouse");
            if(pet instanceof Hamster)
                counter.count("Hamster");
            if(pet instanceof Gerbil)
                counter.count("Gerbil");
        }
        // Show the counts:
        System.out.println("");
        System.out.println(counter);
    }
    public static void main(String[] args) {
        countPets(new ForNameCreator());
    }
}


